package org.someone.blending;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.someone.common.CustomMaths;

public class BlendingCoal {
	
	public static String VAL_FIXED = "1";
	
	public static String VAL_ACTIVITY = "0";

	//BlendingCoal Generator parameter key : FIXED 
	public static String PARA_KEY_FIXED  = "FIXED";
	//BlendingCoal Generator parameter key : ACTIVITY
	public static String PARA_KEY_ACTIVITY = "ACTIVITY";
	//BlendingCoal Generator parameter key : Generator CODE
	public static String PARA_KEY_GENERATORCODE = "GENERATORCODE";
	//BlendingCoal Generator parameter key : SPECIFICATIONS
	public static String PARA_KEY_SPECIFICATIONS = "SPECIFICATIONS";
	//BlendingCoal Generator parameter key : RATIO
	public static String PARA_KEY_RATIO = "RATIO";
	
	//BlendingCoal Generator parameter key : GENERATORQUANTITY
	public static String PARA_KEY_GENERATORQUANTITY = "GENERATORQUANTITY";
	
	public static String SUFFIX_FIXED = "_FIXED";
	
	public static double dbRatioMode = 10;
	/**
	 * 
	 * @param mquantity	数量的map
	 * @return	各key对应的比例
	 */
	public Map<String,String> countRatio(Map<String,String> mquantity){
		int spsize = mquantity.entrySet().size();
		Map<String,String> mratio = new HashMap<String,String>();	//煤种余量配比
		Iterator<Entry<String, String>> quait = mquantity.entrySet().iterator();
		double sumQuantity = sumQauntity(mquantity);
		double sumRatio = 0;
		int spnum = 0;
		while(quait.hasNext()){
			Entry<String, String> e = (Entry<String, String>)quait.next();
			String key = e.getKey();
			double dbQuantity = e.getValue()==null||"".equals(e.getValue())?0:Double.parseDouble(e.getValue());
			double dbRatio =  CustomMaths.round(dbQuantity/sumQuantity*dbRatioMode,0);
			if(++spnum == spsize){
				dbRatio = dbRatioMode - sumRatio;
			}else{
				sumRatio += dbRatio;
			}
			mratio.put(key, String.valueOf(dbRatio));
		}
		return mratio;
	}
	/**
	 * 
	 * @param mquantity	数量的map
	 * @return 总量
	 */
	public double sumQauntity(Map<String,String> mquantity){
		Iterator<Entry<String, String>> quait = mquantity.entrySet().iterator();
		double sumQua = 0;
//		计算总剩余煤量
		while(quait.hasNext()){
			Entry<String, String> e = (Entry<String, String>)quait.next();
			double dbQuantity = e.getValue()==null||"".equals(e.getValue())?0:Double.parseDouble(e.getValue());
			sumQua += dbQuantity;
		}
		return sumQua;
	}
	/**
	 * 
	 * @param t			可分配的原始map
	 * @param mquantity	现有量的map
	 * @param subvalue	分配值
	 */
	public double allocateQuantity(Map<String,String> t, Map<String,String> mquantity, double dbvalue){
		double dbsub = dbvalue ;
		Iterator<Entry<String, String>> tmp = t.entrySet().iterator();
		while(tmp.hasNext()){
			Entry<String, String> etmp = (Entry<String, String>)tmp.next();
			String keytmp = etmp.getKey();
			if(PARA_KEY_GENERATORCODE.equalsIgnoreCase(keytmp))continue;
			double valtmp = etmp.getValue()==null||"".equals(etmp.getValue())?0:Double.parseDouble(etmp.getValue());
			double quatmp = mquantity.get(keytmp)==null||"".equals(mquantity.get(keytmp))?0:Double.parseDouble(mquantity.get(keytmp));
			if(quatmp > dbsub){
				etmp.setValue(String.valueOf(valtmp + dbsub));
				mquantity.put(keytmp, String.valueOf(quatmp - dbsub));
				dbsub = 0;
				break;
			}
		}
		return dbsub;
	}
	/**
	 * 
	 * @param sumquantity	总煤量
	 * @param genset		机组的配置
	 * @param fixed			各机组的固定配比
	 * @param ratio			各煤种比例
	 * @return
	 * @throws Exception
	 */
	public List<Map<String,String>> Calculation(double sumquantity, List<Map<String,String>> genset, List<Map<String,String>> fixed, Map<String,String> ratio) throws Exception{
		Map<String,String> mquantity = new HashMap<String,String>();	//煤种余量
//		Map<String,String> mquantitytmp = new HashMap<String,String>();	//煤种余量
		Map<String,String> mratio = new HashMap<String,String>();	//煤种余量配比
//		根据比例计算煤种余量
		double ActGeneratorNum = 0;
		Iterator<Entry<String, String>> it = ratio.entrySet().iterator();
		while(it.hasNext()){
			Entry<String, String> e = (Entry<String, String>)it.next();
			double val = e.getValue()==null||"".equals(e.getValue())?0:Double.parseDouble(e.getValue());
			val = CustomMaths.round(sumquantity * val / dbRatioMode,2);
			mquantity.put(e.getKey(), String.valueOf(val));
//			mquantitytmp.put(e.getKey(), String.valueOf(val));
		}
		
//		int spsize = mquantity.entrySet().size();
//		确认参与配煤的机组（包括固定配比）
		List<Map<String,String>> valtable = new ArrayList<Map<String,String>>();
		for(int i=0; i< genset.size(); i++){
			Map<String,String> t = genset.get(i);
			boolean isActivity = false;
			if(VAL_ACTIVITY.equals(t.get(PARA_KEY_ACTIVITY))){
				isActivity = true;
			}else if(VAL_FIXED.equals(t.get(PARA_KEY_FIXED))){
				isActivity = true;
			}
			if(isActivity){
				Map<String,String> tmp = new HashMap<String,String>();
				tmp.putAll(genset.get(i));
				valtable.add(t);
			}
		}
		ActGeneratorNum = valtable.size();
//		写入固定配比
		for(int i=0; i< ActGeneratorNum; i++){
			double generatorQuantity = 0;
			Map<String,String> t = valtable.get(i);
			//如果是固定配比的机组
			if(VAL_FIXED.equals(t.get(PARA_KEY_FIXED))){
				//循环固定配比机组的map
				for(int f=0; f< fixed.size(); f++){
					Map<String,String> fd = fixed.get(f);
					//如果是固定配比的原煤仓
					if(fd.get(PARA_KEY_GENERATORCODE).equals(t.get(PARA_KEY_GENERATORCODE))){
						Iterator<Entry<String, String>> fixit = fd.entrySet().iterator();
						double ratiocount = 0;
						//如果当前煤量不满足固定配比的要求 即按配比计算出的煤量 比 实际煤量大 将差值计入dbsub
						double dbsub = 0.0;
						while(fixit.hasNext()){
							Entry<String, String> e = (Entry<String, String>)fixit.next();
							String key = e.getKey();
							if(PARA_KEY_GENERATORCODE.equals(key)) continue;
							String ratvalue = e.getValue();
							double dbRatio = ratvalue == null||"".equals(ratvalue)?0:Double.parseDouble(ratvalue);
							//剩余煤量
							double dbQuantity = mquantity.get(key)==null||"".equals(mquantity.get(key))?0:Double.parseDouble(mquantity.get(key));
							//计算出的煤量
							double dbvalue = CustomMaths.round((sumquantity/ActGeneratorNum)*dbRatio/dbRatioMode,2);
							
							if(dbvalue > dbQuantity){
								if(dbsub > 0){
									throw new Exception("error，Algorithm does not support.");
								}
								dbsub = dbvalue - dbQuantity;
								dbvalue = dbQuantity;
							}
							//更新数量临时map中的数量
							mquantity.put(key, String.valueOf(dbQuantity - dbvalue));
							generatorQuantity += dbvalue + dbsub;
//							t.put(key + SUFFIX_FIXED, String.valueOf(dbvalue));
							t.put(key, String.valueOf(dbvalue));
							ratiocount += dbRatio;
							//判断,将不够耗用的煤量放到其他煤种的耗量中去
							if(dbsub > 0){
								dbsub = allocateQuantity(t, mquantity, dbsub);
							}
						}
						if(ratiocount != dbRatioMode){
							throw new Exception("error，" + t.get(PARA_KEY_GENERATORCODE) + "'s ratio is not equals "+dbRatioMode+".");
						}
					}
				}
			}
			t.put(PARA_KEY_GENERATORQUANTITY, String.valueOf(generatorQuantity));
		}
		
//		计算余煤量及余配比
		mratio.putAll(countRatio(mquantity));
		
//		根据最新配比写入各机组煤量（不包括固定配比机组）
		for(int i=0; i< ActGeneratorNum; i++){
			Map<String,String> t = valtable.get(i);
			double generatorQuantity = 0;
			if(!VAL_FIXED.equals(t.get(PARA_KEY_FIXED))){
				//如果是最后一个原煤仓则剩余煤量全部计入
				if(i+1 == ActGeneratorNum){
					Iterator<Entry<String, String>> qit =  mquantity.entrySet().iterator();
					while(qit.hasNext()){
						Entry<String, String> e = (Entry<String, String>)qit.next();
						String key = e.getKey();
						double dbQuantity = e.getValue()==null||"".equals(e.getValue())?0:Double.parseDouble(e.getValue());
						t.put(key, String.valueOf(dbQuantity));
						generatorQuantity += dbQuantity;
					}
				}else{
					Iterator<Entry<String, String>> nofix = mratio.entrySet().iterator();
					boolean recountratio = false;
					while(nofix.hasNext()){
						double dbsub = 0.0;
						Entry<String, String> e = (Entry<String, String>)nofix.next();
						String key = e.getKey();
						//比例
						double dbRatio = e.getValue()==null||"".equals(e.getValue())?0:Double.parseDouble(e.getValue());
						//分配煤量
						double dbvalue = CustomMaths.round(sumquantity / ActGeneratorNum * dbRatio / dbRatioMode,2);
						//剩余煤量
						double dbQuantity = mquantity.get(key)==null||"".equals(mquantity.get(key))?0:Double.parseDouble(mquantity.get(key));
						if(dbQuantity < dbvalue){
							dbsub = dbvalue - dbQuantity;
							recountratio = true;
							dbvalue = dbQuantity ;
							allocateQuantity(t, mquantity, dbsub);
						}
						//更新数量临时map中的数量
						mquantity.put(key, String.valueOf(dbQuantity - dbvalue));
						generatorQuantity += dbvalue + dbsub;
						t.put(key, String.valueOf(dbvalue));
					}
					if(recountratio){
						mratio.putAll(countRatio(mquantity));
					}
				}
			}
			t.put(PARA_KEY_GENERATORQUANTITY, String.valueOf(generatorQuantity));
		}
		/*
//		计算余煤量
		quait = mquantity.entrySet().iterator();
		sumQua = 0;
		while(quait.hasNext()){
			Entry<String, String> e = (Entry<String, String>)quait.next();
			String key = e.getKey();
			double dbQuantity = e.getValue()==null||"".equals(e.getValue())?0:Double.parseDouble(e.getValue());
			for(int i=0; i< valtable.size(); i++){
				Map<String,String> t = valtable.get(i);
				if(!VAL_FIXED.equals(t.get(PARA_KEY_FIXED))){
					double Quantity = t.get(key)==null||"".equals(t.get(key))?0:Double.parseDouble(t.get(key));
					dbQuantity -= Quantity;
				}
			}
			sumQua += dbQuantity;
			e.setValue(String.valueOf(dbQuantity));
		}
//		计算
		for(int i=0; i<valtable.size(); i++){
			Map<String,String> t = valtable.get(i);
			if(!VAL_FIXED.equals(t.get(PARA_KEY_FIXED))){
				quait = mquantity.entrySet().iterator();
				double tmpsumRatio = 0.0;
				spnum = 0;
				while(quait.hasNext()){
					Entry<String, String> e = (Entry<String, String>)quait.next();
					String key = e.getKey();
					double tmpRatio = 0;
					double curQuantity = t.get(key)==null||"".equals(t.get(key))?0:Double.parseDouble(t.get(key));
					double valQuantity = e.getValue()==null||"".equals(e.getValue())?0:Double.parseDouble(e.getValue());
					double tmpQuantity = curQuantity + valQuantity;
					if(++spnum == spsize){
						tmpRatio = dbRatioMode - tmpsumRatio;
					}else if(tmpQuantity >= 0){
						tmpRatio = CustomMaths.round(tmpQuantity/ (sumquantity/ ActGeneratorNum)*dbRatioMode,0);
						tmpsumRatio += tmpRatio;
					}
					
					double ResQuantity = CustomMaths.round(tmpRatio * (sumquantity/ ActGeneratorNum) /dbRatioMode,2);
					t.put(key, String.valueOf(ResQuantity));
					e.setValue(String.valueOf(CustomMaths.round(curQuantity + valQuantity - ResQuantity,2)));
				}
				
			}
			
		}
		*/
		return valtable;
	}
	
	
	
}
